﻿Imports System.Reflection
Imports System.Text

Public Class ClassData
	Implements System.ComponentModel.INotifyPropertyChanged

	Private _name As String
	Private _namespaceName As String
	Private _accessName As String
	Private _inheritsFrom As New List(Of String)
	Private _implements As New List(Of String)
	Private _properties As New List(Of PropertyData)
	Private _methods As New List(Of MethodData)
	Private _events As New List(Of EventData)
	Private _fields As New List(Of FieldData)

	Public Property Name() As String
		Get
			Return _name
		End Get
		Set(ByVal value As String)
			_name = value
		End Set
	End Property
	Public Property NamespaceName() As String
		Get
			Return _namespaceName
		End Get
		Set(ByVal value As String)
			_namespaceName = value
		End Set
	End Property
	Public Property AccessName() As String
		Get
			Return _accessName
		End Get
		Set(ByVal value As String)
			_accessName = value
		End Set
	End Property
	Public Property InheritsFrom() As List(Of String)
		Get
			Return _inheritsFrom
		End Get
		Set(ByVal value As List(Of String))
			_inheritsFrom = value
		End Set
	End Property
	Public ReadOnly Property ImplementsList() As List(Of String)
		Get
			Return _implements
		End Get
	End Property
	Private Function GetClass(ByVal t) As ClassData
		If t >= _inheritsFrom.Count Then
			Return Nothing
		End If
		Dim name = _inheritsFrom(t)
		If Not Window1.classes.ContainsKey(name) Then
			Return Nothing
		End If
		Return Window1.classes(name)
	End Function
	Public ReadOnly Property Properties() As List(Of PropertyData)
		Get
			If Window1._levels > 0 Then
				Dim list As New List(Of PropertyData)
				list.AddRange(_properties.ToArray)
				For t = 0 To Window1._levels - 1
					Dim cls = GetClass(t)
					If cls IsNot Nothing Then
						list.AddRange(cls._properties.ToArray)
					End If
				Next
				Return (From x In list Order By x.Name Select x).ToList
			End If
			Return _properties
		End Get
	End Property
	Public ReadOnly Property Methods() As List(Of MethodData)
		Get
			If Window1._levels > 0 Then
				Dim list As New List(Of MethodData)
				list.AddRange(_methods.ToArray)
				For t = 0 To Window1._levels - 1
					Dim cls = GetClass(t)
					If cls IsNot Nothing Then
						list.AddRange(cls._methods.ToArray)
					End If
				Next
				Return (From x In list Order By x.Name Select x).ToList
			End If
			Return _methods
		End Get
	End Property
	Public ReadOnly Property Events() As List(Of EventData)
		Get
			If Window1._levels > 0 Then
				Dim list As New List(Of EventData)
				list.AddRange(_events.ToArray)
				For t = 0 To Window1._levels - 1
					Dim cls = GetClass(t)
					If cls IsNot Nothing Then
						list.AddRange(cls._events.ToArray)
					End If
				Next
				Return (From x In list Order By x.Name Select x).ToList
			End If
			Return _events
		End Get
	End Property
	Public ReadOnly Property Fields() As List(Of FieldData)
		Get
			If Window1._levels > 0 Then
				Dim list As New List(Of FieldData)
				list.AddRange(_fields.ToArray)
				For t = 0 To Window1._levels - 1
					Dim cls = GetClass(t)
					If cls IsNot Nothing Then
						list.AddRange(cls._fields.ToArray)
					End If
				Next
				Return (From x In list Order By x.Name Select x).ToList
			End If
			Return _fields
		End Get
	End Property
	Public ReadOnly Property SingleList() As List(Of SingleItem)
		Get
			Dim list As New List(Of SingleItem)
			If Window1._window.ctlDisplayProperties.IsChecked Then list.AddRange((From x In Properties Select New SingleItem With {.Name = x.Name, .Text = x.Text}).ToArray)
			If Window1._window.ctlDisplayMethods.IsChecked Then list.AddRange((From x In Methods Select New SingleItem With {.Name = x.Name, .Text = x.Text}).ToArray)
			If Window1._window.ctlDisplayEvents.IsChecked Then list.AddRange((From x In Events Select New SingleItem With {.Name = x.Name, .Text = x.Text}).ToArray)
			If Window1._window.ctlDisplayFields.IsChecked Then list.AddRange((From x In Fields Select New SingleItem With {.Name = x.Name, .Text = x.Text}).ToArray)
			Return (From x In list Order By x.Name Select x).ToList
		End Get
	End Property
	Sub New()
	End Sub
	Sub New(ByVal item As Type, ByVal all As Boolean)
		If item.IsInterface Then
			AccessName = "Interface"
		ElseIf item.IsAbstract Then
			AccessName = "Abstract"
		ElseIf item.IsEnum Then
			AccessName = "Enum "
		Else
			AccessName = "Class"
		End If
		Name = item.Name
		NamespaceName = item.Namespace
		If item.BaseType IsNot Nothing Then
			InheritsFrom.AddRange(Inheritance(item))
		End If
		' Implements
		_implements.AddRange((From x In item.GetInterfaces() Distinct Order By x.Name Select x.Name).ToArray)

		' Properties
		Dim props() = item.GetProperties(BindingFlags.DeclaredOnly Or BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.Static)
		Me.Properties.AddRange((From x In props Order By x.Name Select New PropertyData(x, item.Name)).ToArray)

		' Methods
		Dim methods() = item.GetMethods(If(all, BindingFlags.FlattenHierarchy, BindingFlags.DeclaredOnly) Or BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.Static)
		For Each method In methods
			If Not method.IsSpecialName Then
				Me.Methods.Add(New MethodData(method, Name))
			End If
		Next
		Dim mlist = (From x In Me.Methods Order By x.Name Select x).ToArray
		Me.Methods.Clear()
		Me.Methods.AddRange(mlist.ToArray)

		' Events
		Dim events() = item.GetEvents(If(all, BindingFlags.FlattenHierarchy, BindingFlags.DeclaredOnly) Or BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.Static)
		For Each entry In events
			Me.Events.Add(New EventData(entry, Name))
		Next
		Dim elist = (From x In Me.Events Order By x.Name Select x).ToArray
		Me.Events.Clear()
		Me.Events.AddRange(elist.ToArray)

		Dim fields() = item.GetFields(If(all, BindingFlags.FlattenHierarchy, BindingFlags.DeclaredOnly) Or BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.Static)
		For Each entry In fields
			Me.Fields.Add(New FieldData(entry, Name))
		Next
		Dim flist = (From x In Me.Fields Order By x.Name Select x).ToArray
		Me.Fields.Clear()
		Me.Fields.AddRange(flist.ToArray)
	End Sub
	Private Function Inheritance(ByVal item As Type) As String()
		Dim list As New List(Of String)
		While item.BaseType IsNot Nothing AndAlso item.BaseType.Name <> "Object"
			list.Add(item.BaseType.Name)
			item = item.BaseType
		End While
		Return list.ToArray
	End Function
	Public Sub SendNotice()
		RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Properties"))
		RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Methods"))
		RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Events"))
		RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("Fields"))
		RaiseEvent PropertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs("SingleList"))
	End Sub
	Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Public Class SingleItem
	Private _name As String
	Private _text As String
	Public Property Name() As String
		Get
			Return _name
		End Get
		Set(ByVal value As String)
			_name = value
		End Set
	End Property
	Public Property Text() As String
		Get
			Return _text
		End Get
		Set(ByVal value As String)
			_text = Value
		End Set
	End Property

End Class
Public Class PropertyData
	Private _name As String
	Private _typeName As String
	Private _arguments As New List(Of ArgumentData)
	Private _isReadOnly As Boolean
	Private _isWriteOnly As Boolean
	Private _isShared As Boolean = False
	Private _className As String
	Public Property Name() As String
		Get
			Return _Name
		End Get
		Set(ByVal value As String)
			_Name = value
		End Set
	End Property
	Public Property TypeName() As String
		Get
			Return _TypeName
		End Get
		Set(ByVal value As String)
			_TypeName = value
		End Set
	End Property
	Public ReadOnly Property Arguments() As List(Of ArgumentData)
		Get
			Return _arguments
		End Get
	End Property
	Public Property IsReadOnly() As Boolean
		Get
			Return _isReadOnly
		End Get
		Set(ByVal value As Boolean)
			_isReadOnly = value
		End Set
	End Property
	Public Property IsWriteOnly() As Boolean
		Get
			Return _isWriteOnly
		End Get
		Set(ByVal value As Boolean)
			_isWriteOnly = value
		End Set
	End Property
	Public Property IsShared() As Boolean
		Get
			Return _isShared
		End Get
		Set(ByVal value As Boolean)
			_isShared = value
		End Set
	End Property

	Public ReadOnly Property Text() As String
		Get
			Dim sb As New StringBuilder
			If _isShared Then sb.Append("Shared ")
			sb.Append("Property ")
			If _isReadOnly Then
				sb.Append("ReadOnly ")
			ElseIf _isWriteOnly Then
				sb.Append("WriteOnly ")
			End If
			sb.Append(Name)
			If _arguments.Count > 0 Then
				Dim sig As New StringBuilder
				For Each arg In _arguments
					If sig.Length > 0 Then sig.Append(", ")
					sig.Append(arg.Text)
				Next
				sb.Append(String.Format("({0})", sig.ToString))
			End If
			sb.Append(" As ")
			sb.Append(TypeName)
			If Window1._levels > 0 Then
				sb.Append(" (from ")
				sb.Append(_className)
				sb.Append(")")
			End If
			Return sb.ToString
		End Get
	End Property
	Sub New()
	End Sub
	Sub New(ByVal entry As PropertyInfo, ByVal className As String)
		_className = className
		Name = entry.Name
		TypeName = entry.PropertyType.Name
		_isReadOnly = entry.CanRead And Not entry.CanWrite
		_isWriteOnly = entry.CanWrite And Not entry.CanRead
		Dim mi = entry.GetGetMethod(True)
		If mi Is Nothing Then
			mi = entry.GetSetMethod(True)
		End If
		If mi IsNot Nothing Then
			_isShared = mi.IsStatic
			Dim params() = mi.GetParameters
			For Each param In params
				_arguments.Add(New ArgumentData(param))
			Next
		End If
	End Sub
End Class
Public Class MethodData
	Private _name As String
	Private _arguments As New List(Of ArgumentData)
	Private _isShared As Boolean
	Private _isVirtual As Boolean
	Private _returnType As String
	Private _className As String

	Public Property Name() As String
		Get
			Return _Name
		End Get
		Set(ByVal value As String)
			_Name = value
		End Set
	End Property
	Public Property Arguments() As List(Of ArgumentData)
		Get
			Return _Arguments
		End Get
		Set(ByVal value As List(Of ArgumentData))
			_Arguments = value
		End Set
	End Property
	Public Property IsShared() As Boolean
		Get
			Return _isShared
		End Get
		Set(ByVal value As Boolean)
			_isShared = value
		End Set
	End Property
	Public Property IsVirtual() As Boolean
		Get
			Return _isVirtual
		End Get
		Set(ByVal value As Boolean)
			_isVirtual = value
		End Set
	End Property
	Public Property ReturnType() As String
		Get
			Return _returnType
		End Get
		Set(ByVal value As String)
			_returnType = value
		End Set
	End Property
	Public ReadOnly Property Text() As String
		Get
			Dim sb As New StringBuilder
			If _isShared Then
				sb.Append("Shared ")
			End If
			If _isVirtual Then
				sb.Append("Overridable ")
			End If
			If _returnType <> String.Empty Then
				sb.Append("Function ")
			Else
				sb.Append("Sub ")
			End If
			sb.Append(_Name)
			sb.Append("(")
			Dim first = True
			For Each arg In _Arguments
				If Not first Then sb.Append(", ")
				first = False
				sb.Append(arg.Text)
			Next
			sb.Append(")")
			If _returnType <> String.Empty Then
				sb.Append(" As ")
				sb.Append(_returnType)
			End If
			If Window1._levels > 0 Then
				sb.Append(" (from ")
				sb.Append(_className)
				sb.Append(")")
			End If
			Return sb.ToString
		End Get
	End Property

	Sub New()
	End Sub
	Sub New(ByVal info As MethodInfo, ByVal className As String)
		_className = className
		_Name = info.Name
		_returnType = If(info.ReturnType IsNot Nothing AndAlso info.ReturnType.Name <> "Void", info.ReturnType.Name, String.Empty)
		_isShared = info.IsStatic
		_isVirtual = info.IsVirtual
		Dim params() = info.GetParameters()
		For Each param In params
			_Arguments.Add(New ArgumentData(param))
		Next
	End Sub
End Class
Public Class EventData
	Private _name As String
	Private _arguments As New List(Of ArgumentData)
	Private _isShared As Boolean = False
	Private _className As String

	Public Property Name() As String
		Get
			Return _name
		End Get
		Set(ByVal value As String)
			_name = value
		End Set
	End Property
	Public ReadOnly Property Arguments() As List(Of ArgumentData)
		Get
			Return _arguments
		End Get
	End Property
	Public Property IsShared() As Boolean
		Get
			Return _isShared
		End Get
		Set(ByVal value As Boolean)
			_isShared = value
		End Set
	End Property

	Public ReadOnly Property Text() As String
		Get
			Dim sb As New StringBuilder
			If _isShared Then
				sb.Append("Shared ")
			End If
			sb.Append("Event ")
			sb.Append(_name)
			sb.Append("(")
			Dim first = True
			For Each arg In _arguments
				If Not first Then sb.Append(", ")
				first = False
				sb.Append(arg.Text)
			Next
			sb.Append(")")
			If Window1._levels > 0 Then
				sb.Append(" (from ")
				sb.Append(_className)
				sb.Append(")")
			End If
			Return sb.ToString
		End Get
	End Property
	Sub New()
	End Sub
	Sub New(ByVal info As EventInfo, ByVal className As String)
		_className = className
		_name = info.Name
		Dim mi = info.GetRaiseMethod(True)
		If mi IsNot Nothing Then
			_isShared = mi.IsStatic
			Dim params() = mi.GetParameters()
			For Each param In params
				_arguments.Add(New ArgumentData(param))
			Next
		End If
	End Sub
End Class
Public Class FieldData
	Private _name As String
	Private _typeName As String
	Private _constant As Boolean
	Private _shared As Boolean
	Private _isEnum As Boolean
	Private _value As String
	Private _className As String

	Public Property Name() As String
		Get
			Return _name
		End Get
		Set(ByVal value As String)
			_name = value
		End Set
	End Property
	Public Property TypeName() As String
		Get
			Return _typeName
		End Get
		Set(ByVal value As String)
			_typeName = value
		End Set
	End Property
	Public Property Constant() As Boolean
		Get
			Return _constant
		End Get
		Set(ByVal value As Boolean)
			_constant = value
		End Set
	End Property
	Public Property [Shared]() As Boolean
		Get
			Return _shared
		End Get
		Set(ByVal value As Boolean)
			_shared = value
		End Set
	End Property
	Public ReadOnly Property Text() As String
		Get
			Dim sb As New StringBuilder
			If _isEnum Then

			Else
				If _shared Then
					sb.Append("Shared ")
				End If
				If _constant Then
					sb.Append("Const ")
				Else
					sb.Append("Dim ")
				End If
			End If
			sb.Append(_name)
			If _isEnum Then
				sb.Append(" = ")
				sb.Append(_value.ToString)
			Else
				sb.Append(" As ")
				sb.Append(_typeName)
			End If
			If Window1._levels > 0 Then
				sb.Append(" (from ")
				sb.Append(_className)
				sb.Append(")")
			End If
			Return sb.ToString
		End Get
	End Property
	Sub New()
	End Sub
	Sub New(ByVal field As FieldInfo, ByVal className As String)
		_className = className
		_name = field.Name
		_typeName = field.FieldType.Name
		_constant = field.IsLiteral
		_shared = field.IsStatic
		_isEnum = field.DeclaringType.IsEnum
		If _isEnum And _constant Then
			Dim type = [Enum].GetUnderlyingType(field.DeclaringType)
			_value = "&h" + String.Format("{0:x}", Convert.ChangeType([Enum].Parse(field.DeclaringType, field.Name), type, System.Globalization.CultureInfo.InvariantCulture))
		Else
			_isEnum = False
		End If
	End Sub
End Class
Public Class ArgumentData
	Private _name As String
	Private _TypeName As String
	Private _passBy As String
	Private _isOptional As Boolean
	Private _defaultValue As String
	Public Property Name() As String
		Get
			Return _name
		End Get
		Set(ByVal value As String)
			_name = value
		End Set
	End Property
	Public Property TypeName() As String
		Get
			Return _TypeName
		End Get
		Set(ByVal value As String)
			_TypeName = value
		End Set
	End Property
	Public Property IsOptional() As Boolean
		Get
			Return _isOptional
		End Get
		Set(ByVal value As Boolean)
			_isOptional = value
		End Set
	End Property
	Public Property DefaultValue() As String
		Get
			Return _defaultValue
		End Get
		Set(ByVal value As String)
			_defaultValue = value
		End Set
	End Property

	Public ReadOnly Property Text() As String
		Get
			Return If(IsOptional, "Optional ", "") + _passBy + _name + " As " + _TypeName + If(IsOptional, " = " + _defaultValue, "")
		End Get
	End Property
	Sub New()
	End Sub
	Sub New(ByVal param As ParameterInfo)
		_name = param.Name
		_TypeName = param.ParameterType.Name
		If param.IsOut Then
			_passBy = "ByRef "
		Else
			_passBy = "ByVal "
		End If
		_isOptional = param.IsOptional
		If param.DefaultValue IsNot System.DBNull.Value Then
			_defaultValue = param.DefaultValue.ToString
		Else
			_defaultValue = String.Empty
		End If
	End Sub
End Class